import static org.junit.Assert.*;
import java.util.Random;

import org.junit.Test;


public class TestValid {
	UrlValidator url = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	
	@Test
	public void testManual() {
		assertTrue(url.isValid("http://www.google.com"));
		assertTrue(url.isValid("http://www.google.com/"));
		assertTrue(url.isValid("http://www.google.com/more"));
		assertTrue(url.isValid("http://www.google.com/more/more/"));
		assertTrue(url.isValid("http://www.amazon.ca"));
		assertTrue(url.isValid("ftp://www.amazon.ca"));
		assertTrue(url.isValid("https://www.amazon.ca/books"));
		assertFalse(url.isValid("http://www.amazon"));
		assertFalse(url.isValid("amazon"));
		assertFalse(url.isValid("http://www.amazon.ca/../"));
		//assertTrue(url.isValid("www.google.com")); - this fails
	}
	
	
	@Test
	public void testPartitionPlainValid(){
		assertTrue(url.isValid("http://www.google.com"));
		assertTrue(url.isValid("http://www.amazon.com"));
	}
	
	@Test
	public void testPartitionProtocols(){
		assertTrue(url.isValid("https://www.google.com"));
		assertTrue(url.isValid("ftps://www.amazon.com"));
		assertTrue(url.isValid("ftp://www.amazon.com"));
		assertFalse(url.isValid("not valid://www.amazon.com"));
	}
	
	@Test
	public void testPartitionSubdomain(){
		assertTrue(url.isValid("http://www.google.com")); //www
		assertTrue(url.isValid("http://google.com")); //none
		assertTrue(url.isValid("http://tests.google.com")); //subdomain
		assertTrue(url.isValid("http://testone.tests.google.com")); //multiple subdomains
		assertFalse(url.isValid("http://bad domain.google.com")); //bad subdomain
	}
	
	@Test
	public void testPartitionDomain(){
		assertTrue(url.isValid("http://www.google.com"));
		assertFalse(url.isValid("http://www.go/.com")); 
		assertTrue(url.isValid("http://go.com"));
		assertFalse(url.isValid("http://testone.tests?.com"));
		assertFalse(url.isValid("http://bad domain.com"));
		assertFalse(url.isValid("http://www.amazon.zz")); //bad top level domain
		//assertTrue(url.isValid("http://www.amazon.co.uk")); //second level domain- this fails
		//assertTrue(url.isValid("http://www.amazon.org.uk")); //- this fails
	}
	
	@Test
	public void testPartitionCom(){
		assertTrue(url.isValid("http://www.google.com")); // .com
		assertTrue(url.isValid("http://www.google.edu")); // another 3 letter
		assertTrue(url.isValid("http://www.google.net")); // another 3 letter
		assertTrue(url.isValid("http://www.google.biz")); // another 3 letter
		assertTrue(url.isValid("http://www.google.edu")); // another 3 letter 
		assertTrue(url.isValid("http://www.google.mobi")); //4 letters are okay
		//assertTrue(url.isValid("http://www.amazon.co.uk")); //- this fails
		assertFalse(url.isValid("http://www.google.co3")); // illegal char
		assertFalse(url.isValid("http://www.google.thisistoolong"));  //too long
	}
	
	@Test
	public void testPartitionFiles(){
		assertTrue(url.isValid("http://www.google.com/")); // .com
		assertTrue(url.isValid("http://www.google.com/index.php")); // with a file
		assertFalse(url.isValid("http://www.google.com&")); //& sign too early
		//assertTrue(url.isValid("http://www.google.com?test=test")); // one parameter - fails
		//assertTrue(url.isValid("http://www.google.com?test=test&t=test")); // two parameters - fails
		assertFalse(url.isValid("http://www.google.com?test?test")); //parameters done wrong
		assertTrue(url.isValid("http://www.google.com/test/test")); //path
		//assertFalse(url.isValid("http://www.google.com/test/../")); //test path - fails
	}
	
	@Test
	public void testExpectTrue(){
		String[] scheme = {"", "https://", "http://", "ftp://", "irc://"};	
		//full list of schemes available: http://en.wikipedia.org/wiki/URI_scheme#Official_IANA-registered_schemes
		String[] domain = {"www.google.com", "en.wikipedia.org", "www.amazon.co.uk", "bing.com", "mysite.net", "orst.edu"};
		String[] port = {"", ":1", ":12", ":123", ":1234", ":12345"};
		String[] path = {"", "/stuff", "/stuff/morestuff", "/stuff/"};
		String[] query = {"", "?name=Jon", "?search", "?one=yes&two=no"};
		String[] fragment = {"", "#", "#goHere", "#line=1,10"};
		String testUrl;
		Random r = new Random();
		int printGood = 0;			//set to 0 to NOT print good values
		int printBad = 0;			//set to 0 to NOT print bad values
		int countGood = 0;
		int countBad = 0;
		int numTests = 100000;
		for(int i = 0; i < numTests; i++){
			int sch = r.nextInt(5);
			int dom = r.nextInt(6);
			int por = r.nextInt(6);
			int pat = r.nextInt(4);
			int que = r.nextInt(4);
			int fra = r.nextInt(4);
			testUrl = scheme[sch] + domain[dom] + port[por] + path[pat] + query[que] + fragment[fra];
			if(!url.isValid(testUrl) && printBad == 1){
				System.out.println(testUrl + " <--- FAIL");
				countBad++;
			}
			else if(!url.isValid(testUrl) && printBad != 1){
				countBad++;
			}
			else if(printGood == 1){
				System.out.println(testUrl + " <--- PASS");
				countGood++;
			}
			else{
				countGood++;
			}
		}
		System.out.println(countGood + " URL's returned true correctly.");
		System.out.println(countBad + " URL's returned wrongly returned false.");
		System.out.println("Test completed.");
	}
	
	@Test
	public void testExpectFalse(){
		Random r = new Random();
		//here some "" are included to keep variance. all tests should still fail based on the domains
		String[] badScheme = {"httpsecure://", "http:/", "ftp:///", "irc:", "nope://", "NOThttp://"};
		String[] badDomain = {"", "domainfail", "no space", "www.okhere.notatopleveldomain", "bing.qxz", "www.google.123", "b@d.edu"};
		String[] badPort = {":-1", ":123456", ":70000"};
		String[] badPath = {"//stuff", ":stuff/morestuff", "-stuff"};
		String[] badQuery = {"??name=Jon", "?search==something", "?one=yes&&two=no"};
		String[] badFragment = {"^#", "{goHere", "://line=1,10"};
		//good stuff also needed for variance
		String[] scheme = {"", "https://", "http://", "ftp://", "irc://"};	
		//full list of schemes available: http://en.wikipedia.org/wiki/URI_scheme#Official_IANA-registered_schemes
		String[] domain = {"www.google.com", "en.wikipedia.org", "www.amazon.co.uk", "bing.com", "mysite.net", "orst.edu"};
		String[] port = {"", ":1", ":12", ":123", ":1234", ":12345"};
		String[] path = {"", "/stuff", "/stuff/morestuff", "/stuff//"};
		String[] query = {"", "?name=Jon", "?search", "?one=yes&two=no"};
		String[] fragment = {"", "#", "#goHere", "#line=1,10"};
		String testUrl;
		int printGood = 0;			//set to 0 to NOT print good values
		int printBad = 0;			//set to 0 to NOT print bad values
		int countGood = 0;
		int countBad = 0;
		int numTests = 100000;
		for(int i = 0; i < numTests; i++){
			int bsch = r.nextInt(6);
			int bdom = r.nextInt(7);
			int bpor = r.nextInt(3);
			int bpat = r.nextInt(3);
			int bque = r.nextInt(3);
			int bfra = r.nextInt(3);
			int sch = r.nextInt(5);
			int dom = r.nextInt(6);
			int por = r.nextInt(6);
			int pat = r.nextInt(4);
			int que = r.nextInt(4);
			int fra = r.nextInt(4);
			int pickBad = r.nextInt(6);
			if(pickBad == 0){
				testUrl = badScheme[bsch] + domain[dom] + port[por] + path[pat] + query[que] + fragment[fra];
			}
			else if (pickBad == 1){
				testUrl = scheme[sch] + badDomain[bdom] + port[por] + path[pat] + query[que] + fragment[fra];
			}
			else if (pickBad == 2){
				testUrl = scheme[sch] + domain[dom] + badPort[bpor] + path[pat] + query[que] + fragment[fra];
			}
			else if (pickBad == 3){
				testUrl = scheme[sch] + domain[dom] + port[por] + badPath[bpat] + query[que] + fragment[fra];
			}
			else if (pickBad == 4){
				testUrl = scheme[sch] + domain[dom] + port[por] + path[pat] + badQuery[bque] + fragment[fra];
			}
			else{
				testUrl = scheme[sch] + domain[dom] + port[por] + path[pat] + query[que] + badFragment[bfra];
			}
			if(url.isValid(testUrl) && printBad == 1){
				System.out.println(testUrl + " <--- FAIL");
				countBad++;
			}
			else if(url.isValid(testUrl) && printBad != 1){
				countBad++;
			}
			else if(printGood == 1){
				System.out.println(testUrl + " <--- PASS");
				countGood++;
			}
			else{
				countGood++;
			}
		}
		System.out.println(countGood + " URL's returned false correctly.");
		System.out.println(countBad + " URL's returned wrongly returned true.");
		System.out.println("Test completed.");
	}
	
}
